package ar.edu.unq.tpi.pconc.tpconcurbattle;

import java.util.List;
import java.util.Random;

import ar.edu.unq.tpi.pconc.Channel;
import ar.edu.unq.tpi.pconc.tpconcurbattle.utils.Util;

public class Unidad implements Runnable {
	
	private String GUIid;
	private int nivel;
	private int batallasGanadas;
	private Bando perteneceA;
	private Ciudad ubicacion;
	public boolean conVida;
	public boolean enCamino;
	
	public Unidad(Bando perteneceA) {
		super();
		this.nivel = 1;
		this.batallasGanadas = 0;
		this.perteneceA = perteneceA;
		this.ubicacion = perteneceA.getUbicacionInicialUnidad();
		this.conVida = true;
		
		Channel<String> serverReceive = new Channel<String>(Util.SERVER_CHANNEL_RECIEVE);
		Channel<Integer> serverSend = new Channel<Integer>(Util.SERVER_CHANNEL_SEND);
		
		serverReceive.send("new");
		int n = serverSend.receive();
		
		this.GUIid = perteneceA.getNombre() + n;
	}
	
	public Unidad(String GUIid,String nivel, String batallasGanadas, String perteneceA, String ubicacion) {
		super();
		this.GUIid = GUIid;
		this.nivel = Integer.parseInt(nivel);
		this.batallasGanadas = Integer.parseInt(batallasGanadas);
		Tablero instance = Tablero.getInstance();
		this.perteneceA = instance.getBando(perteneceA);
		this.ubicacion = instance.getCiudad(ubicacion);
		this.conVida = true;
	}

	public String getGUIid() {
		return GUIid;
	}

	public void setGUIid(String gUIid) {
		GUIid = gUIid;
	}

	public int getNivel() {
		return nivel;
	}

	private void setNivel(int nivel) {
		this.nivel = nivel;
	}

	public int getBatallasGanadas() {
		return batallasGanadas;
	}

	public Bando getPerteneceA() {
		return perteneceA;
	}
	
	public Ciudad getUbicacion() {
		return this.ubicacion;
	}

	public void setUbicacion(Ciudad ubicacion) {
		this.ubicacion = ubicacion;
	}
	
	/** Sube el nivel de la Unidad segun la susecion de numeros de Fibonacci**/
	public void chequearYSubirNivel() {
		this.setNivel(Util.fibonacci(this.getBatallasGanadas()));
	}

	public void ganoBatalla() {
		this.batallasGanadas ++;
		this.chequearYSubirNivel();
	}
	
	public void planificarConquista(Ciudad proximoDestino) {
		if(proximoDestino.getTomadaPor() == null
				|| !proximoDestino.hayAlguien()) {
			this.conquistarDestino(proximoDestino);
		} else {
			this.pelear(proximoDestino);
		}
	}

	private void conquistarDestino(Ciudad proximoDestino) {
		this.mover(proximoDestino);
		proximoDestino.setTomadaPor(this.getPerteneceA());
		System.out.println(proximoDestino.getId() + " tomada por " + this.getGUIid());
		this.getPerteneceA().generarUnidad();
	}

	private void mover(Ciudad proximoDestino) {
		Channel<String> guiSend = new Channel<String>(Util.GUI_RECIEVE);
		guiSend.send(this.getGUIid() + " " + this.getUbicacion().getId());
		
		this.setUbicacion(proximoDestino);
		proximoDestino.agregarUnidad(this);
	}
	
	public void pelear(Ciudad proximoDestino) {
		while (proximoDestino.hayAlguien() && this.conVida) {
			// TODO revisar que el enemigo se quede en donde est�
			Unidad enemigo = proximoDestino.getPrimeraUnidad();
			float factor = this.getNivel()/(this.getNivel() + enemigo.getNivel());
			float random = new Random().nextFloat();
			if(random > factor) {
				enemigo.morir();
				this.ganoBatalla();
				this.conquistarDestino(proximoDestino);
			} else {
				this.morir();
				enemigo.ganoBatalla();
			}
		}
	}
	
	/** Pregunta:
	 *  si proximoDestino no esta tomada y si proximoDestino esta tomada por la unidad a mover
	 *  entonces se mueve sino empieza a planificarConquista**/
	public void chequearMover(Ciudad proximoDestino) {
		boolean mover = proximoDestino.getTomadaPor() != null
				&& this.getPerteneceA().equals(proximoDestino.getTomadaPor());
		
		if(mover) {
			this.mover(proximoDestino);
		} else {
			this.planificarConquista(proximoDestino);
		}
	}
	
	public void morir() {
		this.conVida = false;
		this.getUbicacion().quitarUnidad(this);
		Channel<String> guiSend = new Channel<String>(Util.GUI_RECIEVE);
		guiSend.send(this.getGUIid());
		if(this.getNivel() > 1) {
			this.getPerteneceA().generarUnidad();
		}
		System.out.println("La unidad " + this.getGUIid() + " ha muerto");
	}

	private void dirigirseA(Ciudad proximoDestino) {
		this.getUbicacion().bloquear();
		
		proximoDestino.getRecepcionDeUnidades().send(
				this.GUIid + " " +
				this.nivel + " " +
				this.batallasGanadas + " " +
				this.perteneceA.getNombre() + " " +
				this.ubicacion.getId() + " "
				);
		this.getUbicacion().quitarUnidad(this);
		this.enCamino = true;
		
		this.getUbicacion().desbloquear();
	}
	
	@Override
	public void run() {
		this.enCamino = false;
		Tablero tablero = Tablero.getInstance();
		while(this.conVida && tablero.sinFinalizarJuego() && !this.enCamino) {
			try {
//				Thread.sleep(new Random().nextInt(1000));
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			List<Ciudad> destinos = this.getUbicacion().getDestinos();
			
			Ciudad proximoDestino = destinos.get(new Random().nextInt(destinos.size()));
			this.dirigirseA(proximoDestino);
		}
//		if(!tablero.sinFinalizarJuego() && !tablero.getGanador().equals(this.getPerteneceA())) {
//			this.morir();
//		}
	}
	
}
